package com.naiterui.ehp.ps.form.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.form.DesignFormBO;
import com.naiterui.ehp.bp.bo.form.FormConfBO;
import com.naiterui.ehp.bp.bo.form.FormDataListBO;
import com.naiterui.ehp.bp.bo.form.FormDrawingBO;
import com.naiterui.ehp.bp.bo.form.FormDrawingOptionBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BaseExceptionCodes;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.exception.ResponseVO;
import com.naiterui.ehp.bp.utils.net.RestHttpUtil;
import com.naiterui.ehp.ps.form.bean.DesignForm;
import com.naiterui.ehp.ps.form.bean.FormConf;
import com.naiterui.ehp.ps.form.bean.FormData;
import com.naiterui.ehp.ps.form.bean.FormDrawing;
import com.naiterui.ehp.ps.form.mongo.DesignFormDao;
import com.naiterui.ehp.ps.form.mongo.FormDataDao;
import com.naiterui.ehp.ps.form.service.IDesignFormService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
@RequiredArgsConstructor
public class DesignFormServiceImpl implements IDesignFormService {

    private final DesignFormDao designFormDao;
    private final FormDataDao formDataDao;

    @Value("${file.base.prefix}")
    private String fileBasePrefix;

    @Value("${ehp.domain.img}")
    private String imgHost;

    @Override
    public DesignFormBO getDesignFormVO(String formId) {

        DesignFormBO designFormBO = new DesignFormBO();
        DesignForm designForm = this.designFormDao.getByFormId(formId);
        if (designForm == null) {
            return null;
        }

        FormConfBO formConf = new FormConfBO();
        BeanUtils.copyProperties(designForm.getFormConf(), formConf);

        // formConf.setAction(this.userHost + "/form/" + formId + "/" + businessId);
        // formConf.setUploadFileUrl(this.userHost + "/form/upload");
        designFormBO.setFormConf(formConf);

        List<FormDrawingBO> formDrawings = Lists.newArrayList();
        List<FormDrawing> formDrawing = designForm.getFormDrawing();
        formDrawing.forEach(drawing -> {
            FormDrawingBO formDrawingBO = new FormDrawingBO();
            BeanUtils.copyProperties(drawing, formDrawingBO);
            formDrawingBO.setOptions(CollectionUtils.isEmpty(drawing.getOptions()) ? null
                : drawing.getOptions().stream()
                    .map(opt -> new FormDrawingOptionBO(opt.getOptionLabel(), opt.getOptionValue()))
                    .collect(Collectors.toList()));
            formDrawings.add(formDrawingBO);
        });
        designFormBO.setFormDrawing(formDrawings);
        return designFormBO;
    }

    @Override
    public DesignFormBO getDesignFormDataVO(String formId, String businessId) throws BusinessException {

        DesignFormBO designFormBO = this.getDesignFormVO(formId);

        if (designFormBO == null) {
            log.warn("表单设计不存在 formId:{} businessId:{}", formId, businessId);
            throw new BusinessException(BaseExceptionCodes.DESIGN_FORM_NOT_EXIST);
        }

        designFormBO.setFormId(formId);

        List<FormData> formDatas = this.formDataDao.getFormData(formId, businessId);
        if (CollectionUtils.isEmpty(formDatas)) {
            return designFormBO;
        }

        if (designFormBO.getFormConf().getType() != null && designFormBO.getFormConf().getType() == 2) {
            List<FormDrawingBO> formDrawing = designFormBO.getFormDrawing();
            FormDrawingBO formDrawingVO = null;
            for (FormDrawingBO f : formDrawing) {
                if (Optional.ofNullable(f.getTitle()).orElse(false)) {
                    formDrawingVO = f;
                }
            }
            if (formDrawingVO == null) {
                throw new BusinessException(BaseExceptionCodes.DESIGN_FORM_DRAWING_NOT_EXIST);
            }
            String fieldName = formDrawingVO.getInputname();
            log.debug("多表单标题字段 {}", fieldName);
            List<FormDataListBO> collect = formDatas.stream()
                .map(formData -> new FormDataListBO(formData.getId(), formData.getFormData().get(fieldName).toString()))
                .collect(Collectors.toList());
            designFormBO.setLists(collect);
        } else {

            List<FormDataListBO> collect = formDatas.stream()
                .map(formData -> new FormDataListBO(formData.getId(), designFormBO.getFormConf().getTitle()))
                .collect(Collectors.toList());
            designFormBO.setLists(collect);
        }

        Map<String, Map<String, Object>> formDataMap =
            formDatas.stream().collect(Collectors.toMap(FormData::getId, FormData::getFormData, (a, b) -> b));
        designFormBO.setFormData(formDataMap);

        return designFormBO;
    }

    @Override
    public String saveDesignForm(DesignFormBO designFormBO) {
        DesignForm designForm = new DesignForm();
        designForm.setId(designFormBO.getFormId());
        FormConfBO formConfVO = designFormBO.getFormConf();
        FormConf formConf = new FormConf();
        if (formConfVO != null) {
            BeanUtils.copyProperties(formConfVO, formConf);
        }
        designForm.setFormConf(formConf);
        List<FormDrawing> formDrawings = Lists.newArrayList();

        List<FormDrawingBO> formDrawing = designFormBO.getFormDrawing();
        formDrawing.forEach(formDrawingVO -> {
            FormDrawing drawing = new FormDrawing();
            BeanUtils.copyProperties(formDrawingVO, drawing);
            formDrawings.add(drawing);
        });
        designForm.setFormDrawing(formDrawings);

        this.designFormDao.save(designForm);
        return designForm.getId();
    }

    @Override
    public String copyDesignForm(String formId) {
        DesignForm designForm = this.designFormDao.getByFormId(formId);
        designForm.setId(null);
        this.designFormDao.save(designForm);
        return designForm.getId();
    }

    @Override
    public void saveData(String formId, String businessId, Map<String, Object> data) throws BusinessException {
        DesignForm designForm = this.designFormDao.getByFormId(formId);
        // Object dataId = data.get("id");
        // Integer type = designForm.getFormConf().getType();
        if (this.formDataDao.existFormIdAndBusinessId(formId, businessId)) {
            log.info("单表单只能填写一次 formId:{} businessId:{}", formId, businessId);
            return;
        }

        FormData formData = new FormData();
        //
        // if (dataId != null) {
        // formData.setId((String)dataId);
        // data.remove("id");
        // }
        formData.setFormId(formId);
        formData.setBusinessId(businessId);
        formData.setFormData(data);
        this.formDataDao.save(formData);

        // 清楚缓存
        deleteCacheFormData(businessId, formId);
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("formId", formId);
        paramMap.put("businessId", businessId);
        paramMap.put("dataId", formData.getId());
        paramMap.put("status", "SUCCESS");
        String callBack = designForm.getFormConf().getCallBack();
        if (StringUtils.isNotBlank(callBack)) {
            RestHttpUtil.post().url(callBack).paramMap(paramMap)
                .executeData(new ParameterizedTypeReference<ResponseVO<String>>() {});
        }
    }

    @Override
    public String uploadFile(MultipartFile file) throws BusinessException {
        String path = "/" + this.fileBasePrefix + "/form/";
        String[] split = Objects.requireNonNull(file.getOriginalFilename()).split("\\.");
        String fileName = UUID.randomUUID() + "." + split[split.length - 1];
        try {
            FileUtils.copyInputStreamToFile(file.getInputStream(), new File(path + fileName));
        } catch (IOException e) {
            log.info("上传设计表单文件时出现异常: {}", e.getMessage());
            throw new BusinessException(BaseExceptionCodes.DESIGN_FORM_UPLOAD_FILE_ERROR);
        }
        return String.format("%s/form/%s", this.imgHost, fileName);
    }

    @Override
    public String cloneDesignForm(String sourceId, String targetId) {
        DesignForm sourceDesignForm = this.designFormDao.getByFormId(sourceId);
        DesignForm targetDesignForm = this.designFormDao.getByFormId(targetId);
        if (targetDesignForm == null || sourceDesignForm == null) {
            return "sourceForm or targetForm not exist";
        }
        targetDesignForm.setFormDrawing(sourceDesignForm.getFormDrawing());
        this.designFormDao.save(targetDesignForm);
        return "complete";
    }

    @Override
    public void saveCacheFormData(String businessId, String formId, Map<String, Object> data) {
        String formKey = String.join("_", businessId, formId);
        RedisUtil.valueOps().set(CommonConstant.DESIGN_FORM_DATA_CHCHE_KEY + formKey, data,
            CommonConstant.DESIGN_FORM_DATA_CHCHE_KEY_EXPIRED);
    }

    @Override
    public Map<String, Object> getCacheFormData(String businessId, String formId) {
        String formKey = String.join("_", businessId, formId);
        return (Map<String, Object>)RedisUtil.valueOps().getObject(CommonConstant.DESIGN_FORM_DATA_CHCHE_KEY + formKey);
    }

    private void deleteCacheFormData(String businessId, String formId) {
        String formKey = String.join("_", businessId, formId);
        RedisUtil.keyOps().delete(CommonConstant.DESIGN_FORM_DATA_CHCHE_KEY + formKey);
    }

}
